/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * @brief map-messenger /map-messenger/src/MapSocket.cpp
 * Copyright (C) Matheus Neder, Amanda Duarte, Priscila Cardoso 2010
 * 
 * MapSocket.cpp is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MapSocket.cpp is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @brief map-messenger /map-messenger/src/MapSocket.cpp
 * @file MapSocket.cpp
 * @date 14/06/2010
 * @author Matheus Neder <matheusneder@gmail.com>
 * @author Amanda Duarte <mandinhaduarte89@gmail.com>
 * @author Priscila Cardoso <japinha-htinha@hotmail.com>
 */

#include "MapSocket.h"
#include "Crypto.h"
#include "GuiInterface.h"
#include "MapInteger.h"

#include <cstring>
#include <iostream>
#include <cstdio>

extern GuiInterface* gui;
extern Crypto* cpr;
extern Glib::ustring usernameConnectedWith;

void MapSocket::readUsernameConnectedWith(tcp::socket* sock)
{
	using namespace std;
	const static int MAX_LENGTH = 1024;
	static char data[MAX_LENGTH];
	boost::system::error_code error;
	size_t length;
	try
	{
		//for (;;)
		//{
		length = sock->read_some(boost::asio::buffer(data), error);
		if (error == boost::asio::error::eof)
		{
			//TODO: exibir mensagem em caixa de dialogo
			cerr << "Connexao fechada" << endl;
			//break; // Connection closed cleanly by peer.
		}
		else if (error)
			throw boost::system::system_error(error); // Some other error.
		//cout << data << endl;
		//data[length] = '\0';
		//			gui->chatAreaInsertMessage(usernameConnectedWith, cpr->transform(
		//					data, length));
		usernameConnectedWith = cpr->transform(data, length);
		std::cout << "* Recebido nome do usuario a quem esta se conectando: " << std::endl;
		//std::cout << std::endl;
		for (int i = 0; i < (int) length; i++)
		{
			printf("%#x ", data[i]);
		}
		//std::cout << std::endl;
		std::cout << std::endl;

		//}
	} catch (boost::system::system_error& e)
	{
		//TODO: exibir mensagem em caixa de diagolo
		cerr << "Excecao em : MapSocket::readUsernameConnectedWith" << e.what() << endl;
	}
}

void MapSocket::read(SocketSharedPtr sock)
{
	using namespace std;
	const static int MAX_LENGTH = 1024;
	static char data[MAX_LENGTH];
	boost::system::error_code error;
	size_t length;
	try
	{
		for (;;)
		{
			length = sock->read_some(boost::asio::buffer(data), error);
			if (error == boost::asio::error::eof)
			{
				//TODO: exibir mensagem em caixa de dialogo
				gui->fatalErrorDialog("A conexão foi fechada pela outra ponta.");
				//cerr << "Connexao fechada" << endl;
				break; // Connection closed cleanly by peer.
			}
			else if (error)
				throw boost::system::system_error(error); // Some other error.
			//cout << data << endl;
			//data[length] = '\0';
			gui->chatAreaInsertMessage(usernameConnectedWith, cpr->transform(
					data, length));
			std::cout << "* Mensagem recebida: " << std::endl;
			//std::cout << std::endl;
			for (int i = 0; i < (int) length; i++)
			{
				printf("%#x ", data[i]);
			}
			//std::cout << std::endl;
			std::cout << std::endl;
			gui->getMainWindow()->set_urgency_hint();
			while (Gdk::Event::events_pending())
				Gdk::flush();
		}
	} catch (boost::system::system_error& e)
	{
		//TODO: exibir mensagem em caixa de diagolo
		//cerr << "Excecao na thread readSocket: " << e.what() << endl;
		gui->fatalErrorDialog(Glib::ustring("Ocorreu um erro: ") + e.what());
	}
}

MapInteger MapSocket::plainRead(tcp::socket* sock)
{
	using namespace std;
	const static int MAX_LENGTH = 1024;
	static char data[MAX_LENGTH];
	MapInteger ret = -1;
	boost::system::error_code error;
	size_t length;
	try
	{
		//		for (;;)
		//		{
		length = sock->read_some(boost::asio::buffer(data), error);
		/*if (length != sizeof(MapInteger))
		 {
		 throw std::runtime_error(
		 "Valor lido nao corresponde ao um MapInteger.");
		 }
		 else*/
		if (error == boost::asio::error::eof)
		{
			//TODO: exibir mensagem em caixa de dialogo
			cerr << "Connexao fechada!" << endl;
			//break; // Connection closed cleanly by peer.
		}
		else if (error)
			throw boost::system::system_error(error); // Some other error.

		ret = *((MapInteger*) ((void*) data));
		//cout << data << endl;
		//data[length] = '\0';
		//			gui->chatAreaInsertMessage(usernameConnectedWith, cpr->transform(data, length));
		//			std::cout << "* Mensagem recebida: " << std::endl;
		//			std::cout << std::endl;
		//			for (int i = 0; i < (int)length; i++)
		//			{
		//				printf("%#x ", data[i]);
		//			}
		//			std::cout << std::endl;
		//			std::cout << std::endl;
		//			gui->getMainWindow()->set_urgency_hint();
		//			while (Gdk::Event::events_pending())
		//				Gdk::flush();
		//		}
	} catch (boost::system::system_error& e)
	{
		//TODO: exibir mensagem em caixa de diagolo
		cerr << "Excecao em MapSocket::plainRead: " << e.what() << endl;
	}
	return ret;
}

void MapSocket::write(tcp::socket* sock, const std::string& message)
{
	size_t length;
	try
	{
		int rawDataLen = message.size() + 1 + (sizeof(MapInteger)
				- (message.size() + 1) % sizeof(MapInteger));
		char* aux;
		char* rawData = new char[rawDataLen];
		strcpy(rawData, message.c_str());

		//		length = boost::asio::write(*sock, boost::asio::buffer(message.c_str(),
		//				message.length()));
		aux = rawData;
		rawData = cpr->transform(aux, rawDataLen);
		delete[] aux;
		length = boost::asio::write(*sock, boost::asio::buffer(rawData,
				(size_t) rawDataLen));
		//if (length != message.length())
		std::cout << "* Mensagem enviada: " << std::endl;
		//std::cout << std::endl;
		for (int i = 0; i < rawDataLen; i++)
		{
			printf("%#x ", rawData[i]);
		}
		//std::cout << std::endl;
		std::cout << std::endl;
		delete[] rawData;
		if ((int) length != rawDataLen)
		{
			throw std::runtime_error("Nao foi possivel escrever a mensagem.");
		}
	} catch (std::exception& e)
	{
		//TODO: colocar mensagem em caixa de dialogo
		//std::cerr << "Excecao em MapSocket::write: " << e.what() << std::endl;
		gui->fatalErrorDialog(Glib::ustring("Excecao em MapSocket::write: ") + e.what());
	}
}

void MapSocket::writeUsername(tcp::socket* sock, const std::string& message)
{
	size_t length;
	try
	{
		int rawDataLen = message.size() + 1 + (sizeof(MapInteger)
				- (message.size() + 1) % sizeof(MapInteger));
		char* aux;
		char* rawData = new char[rawDataLen];
		strcpy(rawData, message.c_str());

		//		length = boost::asio::write(*sock, boost::asio::buffer(message.c_str(),
		//				message.length()));
		aux = rawData;
		rawData = cpr->transform(aux, rawDataLen);
		delete[] aux;
		length = boost::asio::write(*sock, boost::asio::buffer(rawData,
				(size_t) rawDataLen));
		//if (length != message.length())
		std::cout << "* Enviado o seu nome: " << std::endl;
		//std::cout << std::endl;
		for (int i = 0; i < rawDataLen; i++)
		{
			printf("%#x ", rawData[i]);
		}
		//std::cout << std::endl;
		std::cout << std::endl;
		delete[] rawData;
		if ((int) length != rawDataLen)
		{
			throw std::runtime_error("Nao foi possivel escrever a mensagem.");
		}
	} catch (std::exception& e)
	{
		//TODO: colocar mensagem em caixa de dialogo
		std::cerr << "Excecao em writeSocket: " << e.what() << std::endl;
	}
}

void MapSocket::plainWrite(tcp::socket* sock, const MapInteger& message)
{
	size_t length;
	try
	{
		//		int rawDataLen = message.size() + 1 + (sizeof(MapInteger)
		//				- (message.size() + 1) % sizeof(MapInteger));
		//		char* aux;
		//		char* rawData = new char[rawDataLen];
		//		strcpy(rawData, message.c_str());
		//
		//		//		length = boost::asio::write(*sock, boost::asio::buffer(message.c_str(),
		//		//				message.length()));
		//		aux = rawData;
		//		rawData = cpr->transform(aux, rawDataLen);
		//		delete[] aux;
		length = boost::asio::write(*sock, boost::asio::buffer(&message,
				(size_t) sizeof(MapInteger)));
		//if (length != message.length())
		//		std::cout << "* Mensagem enviada: " << std::endl;
		//		std::cout << std::endl;
		//		for (int i = 0; i < rawDataLen; i++)
		//		{
		//			printf("%#x ", rawData[i]);
		//		}
		//		std::cout << std::endl;
		//		std::cout << std::endl;
		//		delete[] rawData;
		if ((int) length != sizeof(MapInteger))
		{
			throw std::runtime_error("Nao foi possivel escrever a mensagem.");
		}
	} catch (std::exception& e)
	{
		//TODO: colocar mensagem em caixa de dialogo
		std::cerr << "Excecao em MapSocket::plainWrite: " << e.what()
				<< std::endl;
	}
}
